package com.wuyan.web.auth.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.wuyan.web.auth.entity.PubAccount;
import com.wuyan.web.auth.entity.PubUser;
import com.wuyan.web.auth.form.PubAccountForm;
import com.wuyan.web.auth.form.PubUserForm;
import com.wuyan.web.auth.helper.AuthHelper;
import com.wuyan.web.auth.helper.wx.AccessToken;
import com.wuyan.web.auth.helper.wx.Userinfo;
import com.wuyan.web.auth.service.api.WxAuthApiService;
import com.wuyan.web.base.entity.PubConfig;
import com.wuyan.web.base.helper.PubConfigHelper;
import com.wuyan.web.base.helper.auth.LoginInfo;
import com.wuyan.web.base.helper.rep.RepPageData;
import com.wuyan.web.base.helper.req.CustomQueryHelper;
import com.wuyan.web.base.helper.req.CustomQueryParams;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class LoginService {

    private static final String CONFIG_TYPE_SYSTEM_NAME = "system";
    private static final String CONFIG_TYPE_TOKEN_EXPIRES_IN_NAME = "token-expires-in";

    @Autowired
    private AuthHelper authHelper;

    @Autowired
    private PubAccountService pubAccountService;

    @Autowired
    private PubUserService pubUserService;

    @Autowired
    private PubConfigHelper configHelper;

    @Value(value = "${wuyan.system.token-expires-in}")
    private Long tokenExpiresIn;

    /**
     * 创建账户
     *
     * @param accessToken 授权账户
     * @param userinfo    用户基本信息
     * @return PubAccountForm
     */
    public PubAccount createAccount(AccessToken accessToken, Userinfo userinfo) throws Exception {
        PubAccountForm pubAccountForm = PubAccountForm.builder()
                .username(StringUtils.isBlank(userinfo.getUnionid()) ? accessToken.getOpenid() : userinfo.getUnionid())
                .status(1)
                .openId(accessToken.getOpenid())
                .unionId(userinfo.getUnionid())
                .build();

        return pubAccountService.create(pubAccountForm);
    }

    /**
     * 创建用户基本信息
     *
     * @param userId   用户ID
     * @param userinfo 用户基本信息
     * @return PubUserForm
     */
    public PubUser createUser(Integer userId, Userinfo userinfo) throws Exception {
        PubUserForm pubUserForm = PubUserForm.builder().build();
        BeanUtils.copyProperties(userinfo, pubUserForm);

        pubUserForm.setUserId(userId);
        pubUserForm.setImg(userinfo.getHeadimgurl());

        return pubUserService.create(pubUserForm);
    }

    /**
     * 获取用户基本信息
     *
     * @param userId 用户ID
     * @return PubUser
     */
    public PubUser getUser(Integer userId)
            throws ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, InstantiationException, IllegalAccessException {
        List<CustomQueryParams> params = new ArrayList<>();
        Integer[] right = {userId};
        params.add(CustomQueryParams.builder()
                .left("userId")
                .op("eq")
                .right(right)
                .build());

        CustomQueryHelper<PubUser> queryHelper = CustomQueryHelper.init(PubUser.class, params, new ArrayList<>());
        RepPageData<PubUser> data = pubUserService.page(
                queryHelper.getPredicates(),
                queryHelper.getOrders(),
                false,
                0,
                0
        );

        return null == data.getList() || data.getList().size() < 1 ? null : data.getList().get(0);
    }

    /**
     * 根据openid或者unionId获取账户信息
     * 两者选其一，首选unionId
     *
     * @param openId  第三方开放用户账户唯一标识
     * @param unionId 第三方开放用户账户联合唯一标识
     * @return PubAccount
     */
    public PubAccount getAccountByWx(String openId, String unionId) throws ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, InstantiationException, IllegalAccessException {
        List<CustomQueryParams> params = new ArrayList<>();
        String[] right = {StringUtils.isBlank(unionId) ? openId : unionId};
        params.add(CustomQueryParams.builder()
                .left(StringUtils.isBlank(unionId) ? "openId" : "unionId")
                .op("eq")
                .right(right)
                .build());

        CustomQueryHelper<PubAccount> queryHelper = CustomQueryHelper.init(PubAccount.class, params, new ArrayList<>());
        RepPageData<PubAccount> data = pubAccountService.page(
                queryHelper.getPredicates(),
                queryHelper.getOrders(),
                false,
                0,
                0
        );

        return null == data.getList() || data.getList().size() < 1 ? null : data.getList().get(0);
    }

    /**
     * 获取token的有效期
     *
     * @return long
     */
    public long getTokenExpiresIn() {
        List<PubConfig> list = configHelper.configs(CONFIG_TYPE_SYSTEM_NAME, CONFIG_TYPE_TOKEN_EXPIRES_IN_NAME);

        if (null == list || list.isEmpty()) {
            return tokenExpiresIn;
        }

        return Long.parseLong(list.get(0).getCfgValue());
    }

    /**
     * 保存登录信息
     *
     * @param request    请求体
     * @param response   响应体
     * @param pubAccount 账户信息
     * @return LoginInfo
     * @throws ClassNotFoundException    e
     * @throws NoSuchMethodException     e
     * @throws InstantiationException    e
     * @throws IllegalAccessException    e
     * @throws InvocationTargetException e
     * @throws JsonProcessingException   e
     */
    public LoginInfo saveLoginInfo(HttpServletRequest request, HttpServletResponse response, PubAccount pubAccount)
            throws JsonProcessingException, ClassNotFoundException,
            NoSuchMethodException, InstantiationException,
            IllegalAccessException, InvocationTargetException {
        PubUser pubUser = getUser(pubAccount.getId());
        return saveLoginInfo(request, response, pubAccount, pubUser);
    }

    /**
     * 保存登录信息
     *
     * @param request    请求体
     * @param response   响应体
     * @param pubAccount 账户信息
     * @param pubUser    用户信息
     * @return LoginInfo
     * @throws JsonProcessingException e
     */
    public LoginInfo saveLoginInfo(HttpServletRequest request,
                                   HttpServletResponse response,
                                   PubAccount pubAccount,
                                   PubUser pubUser)
            throws JsonProcessingException {

        com.wuyan.web.base.entity.PubAccount account = com.wuyan.web.base.entity.PubAccount.builder().build();
        com.wuyan.web.base.entity.PubUser user = com.wuyan.web.base.entity.PubUser.builder().build();
        BeanUtils.copyProperties(pubAccount, account);

        if (null != pubUser) {
            BeanUtils.copyProperties(pubUser, user);
        }

        return authHelper.save(request, response, account, user, getTokenExpiresIn());
    }
}
